/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

#include "DirectShowMediaFile.h"


using namespace Scenic::Renderer;


static HRESULT phr;


ImageRenderer::ImageRenderer(Image *image)
	: CBaseVideoRenderer(__uuidof(CLSID_ImageRenderer), 
	NAME("Image Renderer"), NULL, &phr)
{
	printf("ImageRenderer::ImageRenderer %d\n", (int)image);
	this->image = image;
	threadEnv = 0;
	desiredWidth = -1;
	desiredHeight = -1;
}

ImageRenderer::~ImageRenderer()
{
	printf("ImageRenderer::~ImageRenderer\n");
	image->releaseReference();
}

HRESULT ImageRenderer::CheckMediaType(const CMediaType *pmt)
{
	int width, height;

//	printf("ImageRenderer::CheckMediaType\n");
	printf("Format: %s, Type: %s, Subtype: %s\n", GuidNames[pmt->formattype], GuidNames[pmt->majortype], GuidNames[pmt->subtype]);

    HRESULT   hr = E_FAIL;
    
    CheckPointer(pmt,E_POINTER);
	
    // Reject the connection if this is not a video type
    if( pmt->formattype != FORMAT_VideoInfo && pmt->formattype != FORMAT_VideoInfo2) {
        return E_INVALIDARG;
    }
    
    if(!IsEqualGUID( *pmt->Type(),    MEDIATYPE_Video)  ||
		!IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24))
    {
		printf("Media type not ok\n");
        return E_FAIL;
    }
    
	if(pmt->formattype == FORMAT_VideoInfo)
	{
	    VIDEOINFOHEADER *info = (VIDEOINFOHEADER*)pmt->Format();

		width  = info->bmiHeader.biWidth;
	    height = info->bmiHeader.biHeight;
	}
	else
	{
	    VIDEOINFOHEADER2 *info = (VIDEOINFOHEADER2*)pmt->Format();

	    width  = info->bmiHeader.biWidth;
	    height = info->bmiHeader.biHeight;
	}

	printf("width: %d, heigth: %d\n", width, height);

	if(desiredWidth != -1 && (width != desiredWidth || height != desiredHeight))
	{
		printf("fail\n");
		return E_FAIL;
	}
	return S_OK;
}

HRESULT ImageRenderer::SetMediaType(const CMediaType *pmt)
{
	int width, height;
	Synchronized sync(renderingLock);

	printf("ImageRenderer::SetMediaType\n");

	if(pmt->formattype == FORMAT_VideoInfo)
	{
	    VIDEOINFOHEADER *info = (VIDEOINFOHEADER*)pmt->Format();

		width  = info->bmiHeader.biWidth;
	    height = info->bmiHeader.biHeight;
		image->free();
		image->create(width, abs(height), FMT_R8G8B8);
		isUpsideDown = height > 0;
	}
	else
	{
	    VIDEOINFOHEADER2 *info = (VIDEOINFOHEADER2*)pmt->Format();

	    width  = info->bmiHeader.biWidth;
	    height = info->bmiHeader.biHeight;
		image->free();
		image->create(width, abs(height), FMT_R8G8B8);
		isUpsideDown = height > 0;
	}

	printf("width: %d, height: %d\n", width, height);

    return S_OK;
}

HRESULT ImageRenderer::DoRenderSample(IMediaSample *sample)
{
	BYTE *buffer;
    
	CheckPointer(sample,E_POINTER);	
    sample->GetPointer( &buffer );
	if(isUpsideDown)
	{
		Synchronized sync(renderingLock);

		image->write(0, 0, image->width, image->height, (char*)buffer, -image->width * 3, image->format);
	}
	else
	{
		Synchronized sync(renderingLock);

		image->write(0, 0, image->width, image->height, (char*)buffer, image->width * 3, image->format);
	}
	
	image->getJavaVM()->AttachCurrentThread((void**)&threadEnv, NULL);
	jobject obj = image->getJavaObject();

	if(obj)
	{
		jclass clazz = threadEnv->GetObjectClass(obj);
		jmethodID markChangedMethod = threadEnv->GetMethodID(clazz, "markChanged", "()V");

		threadEnv->CallVoidMethod(obj, markChangedMethod);
	}
	image->getJavaVM()->DetachCurrentThread();
	threadEnv = NULL;

    return S_OK;
}

void ImageRenderer::detachThread()
{
	JavaVM *vm = image->getJavaVM();
	JNIEnv *env;

	if(vm->GetEnv((void**)&env, JNI_VERSION_1_4) == JNI_EDETACHED)
	{
		printf("Thread not attached\n");
	}
	else if(env != threadEnv)
	{
		printf("Thread is not rendering thread!\n");
	}
	else
	{
		printf("Detaching rendering thread from VM\n");
		vm->DetachCurrentThread();
		threadEnv = NULL;
	}
}

void ImageRenderer::setDesiredFormat(int width, int height, Format format)
{
	desiredWidth = width;
	desiredHeight = height;
	desiredFormat = format;
}
